package com.cloudy.core.common;


import org.apache.thrift.TProcessor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Constructor;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 *  对thrift接口实现类进行管理
 *  Created by cloudy.xie on 16/11/18.
 */
public class ThriftProcessorManager {
    private Logger logger = LoggerFactory.getLogger(this.getClass());

    private static ThriftProcessorManager instance = new ThriftProcessorManager();
    private ThriftProcessorManager(){}
    public static ThriftProcessorManager getInstance(){
        return instance;
    }

    private Map<String,TProcessor> processorMap = new HashMap<>();
    private Map<String,String> faceNameMap = new HashMap<>();

    public Map<String,TProcessor> getProcessor(){
        return processorMap;
    }

    public String getFaceName(String serviceName){
        if(!faceNameMap.containsKey(serviceName)){
            return null;
        }
        return faceNameMap.get(serviceName);
    }


    {
        List<Class<?>> services = getServices();
        if(services != null && !services.isEmpty()){
            services.forEach(obj->getProcessor(obj));
        }
    }

    /**
     * 根据注解获取thrift 接口实现类
     * @return
     */
    private List<Class<?>> getServices(){
        return ClassUtils.getClasses(ThriftConstants.SERVICE_PACKAGE);
    }

    private void getProcessor(Class<?> serviceClass){
        if (serviceClass == null) {
            return ;
        }

        // 获取实现类接口
        Class<?>[] interfaces = serviceClass.getInterfaces();
        if (interfaces.length <= 0) {
            return ;
        }

        String serviceName = serviceClass.getName();

        String processorName=null;
        TProcessor processor = null;
        for (Class<?> clazz : interfaces) {
            String cname = clazz.getSimpleName();
            if (!cname.equals("Iface")) {
                continue;
            }
            processorName = clazz.getEnclosingClass().getName() ;
            try {
                ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
                Class<?> pclass = classLoader.loadClass(processorName+ "$Processor");
                if (!TProcessor.class.isAssignableFrom(pclass)) {
                    continue;
                }
                Constructor<?> constructor = pclass.getConstructor(clazz);
                processor = (TProcessor) constructor.newInstance(serviceClass.newInstance());
                break;
            } catch (Exception e) {
                logger.error("ClassLoader-error",e);
            }
        }

        if(processor!=null) {
            int start = serviceName.indexOf(ThriftConstants.SERVICE_PACKAGE) + ThriftConstants.SERVICE_PACKAGE.length();
            processorMap.put(serviceName.substring(start+1), processor);
            faceNameMap.put(serviceName.substring(start+1),processorName);
        }else{
            logger.warn("processor-is-null serviceName = {}",serviceName);
        }
    }
}

